package com.displayCongress;

import java.io.BufferedInputStream;
import java.io.ByteArrayOutputStream;
import java.io.DataInputStream;
import java.io.DataOutputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.net.Socket;
import java.net.UnknownHostException;
import java.util.ArrayList;

public class CongressSocket extends Socket implements Runnable
{
	private final int BLOCK_SIZE = 1024;
	
	private DataInputStream inDataStream;
	private DataOutputStream outDataStream;
	
	public CongressSocket(String remoteMachine, int port) throws UnknownHostException, IOException
	{
		super(remoteMachine, port);
		
		InputStream inStream = getInputStream();
		inDataStream = new DataInputStream(inStream);
		
		OutputStream outStream = getOutputStream();
		outDataStream = new DataOutputStream(outStream);
		
		new Thread(this).start();
	}
	
	public boolean send(File f) throws IOException
	{
//		byte[] buffer = new byte[BLOCK_SIZE];
		
		System.out.println(f.getName());
		
		FileInputStream fis = new FileInputStream(f);
		InputStream bis = new BufferedInputStream(fis);
		ByteArrayOutputStream bos = new ByteArrayOutputStream();
		
		boolean result = true;
		
		result &= send("<name>" + f.getName() + "</name><type>file</type><data>");
		
		while (bis.available() > 0 && result)
		{
			bos.write(bis.read());
		}
		
		result &= send(bos.toByteArray());
		
		/*byte[] bytes = bos.toByteArray();
		for (int i = 0; i < bytes.length; i++)
		{
			result &= send(toHex(bytes[i]));
		}*/
		
		result &= send("</data><EOF>");
		
//		result &= send(send.getBytes().length);
//		result &= send(send);
		
		return result;
	}
	
	public boolean send(byte[] bytes)
	{		
		String result = "";
		
		int[] encoded = encode(bytes);
		
		for (int i = 0; i < bytes.length; i++)
		{
			result += toHex(encoded[i]);
		}
		
		System.out.println(result);
		
		return send(result);
	}
	
	private boolean send(String bytes)
	{
		try 
		{
			outDataStream.writeBytes(bytes);
		} 
		catch (IOException e) 
		{
			return false;
		}
		
		return true;
	}
	
	private boolean send(int i)
	{
		try 
		{
			outDataStream.writeInt(i);
		} 
		catch (IOException e) 
		{
			return false;
		}
		
		return true;
	}
	
	public boolean sendEOF()
	{
		try 
		{
			outDataStream.writeBytes("<EOF>");
		} 
		catch (IOException e) 
		{
			return false;
		}
		
		return true;
	}
	
	public synchronized byte[] read()
	{
		ArrayList<Byte> result = new ArrayList<Byte>();
		
		byte[] temp = new byte[BLOCK_SIZE];
		
		try
		{
			while(inDataStream.read(temp) != -1)
			{
				for (byte t : temp)
				{
					result.add(t);
				}
			}
		}
		catch (IOException e) {}
		
		byte[] bytes = new byte[result.size()];
		
		for (int i = 0; i < result.size(); i++)
		{
			bytes[i] = result.get(i);
		}
		
		return bytes;
	}
	
	private int[] encode(byte[] bytes)
	{
		int[] result = new int[bytes.length];
		
		for (int i = 0; i < bytes.length; i++)
		{
			int bits = 0;
		    for (int j = 0; j < 8; j++)
		    {  
		        bits += (int) (!((bytes[i] & (byte) Math.pow(2, j)) > 0) ? Math.pow(2, j) : 0);  
		    }  
		    
			result[i] = bits;
		}
		
		return result;
	}
	
	// Make sure every byte is represented by 2 hexadecimal values
	private String toHex(int v)
	{
		return v > 15 ? Integer.toHexString(v) : "0" + Integer.toHexString(v);
	}

	public void run() 
	{
		while (this.isConnected())
		{
			byte[] read = read();
			if (read.length > 0)
			{
				System.out.println(new String(read));
			}
			
			try 
			{
				Thread.sleep(250);
			} 
			catch (InterruptedException e) {}
		}
		
		try 
		{
			inDataStream.close();
			outDataStream.close();
		} 
		catch (IOException e) {}
	}
}